Skip to content

fix(scripts): prevent command injection in expo-upload-sourcemaps#5636

Merged
antonis merged 2 commits intomainfrom
antonis/RN-485
Feb 10, 2026
Merged

fix(scripts): prevent command injection in expo-upload-sourcemaps#5636
antonis merged 2 commits intomainfrom
antonis/RN-485

Conversation

@antonis
Copy link
Contributor

@antonis antonis commented Feb 9, 2026

📢 Type of change

  • Bugfix
  • New feature
  • Enhancement
  • Refactoring

📜 Description

Replaced execSync with spawnSync to eliminate shell command injection vulnerability. Arguments are now passed as an array directly to the binary, preventing any shell metacharacter interpretation.

Security improvements:

  • No shell invocation - uses spawnSync instead of execSync
  • Arguments passed as array, not string concatenation
  • Eliminates need for platform-specific escaping
  • Immune to command injection by design

Added comprehensive test suite with 12 tests covering:

  • Basic functionality (uploads, error handling)
  • Security (command injection prevention)
  • Hermes support (--debug-id-reference flag)
  • Environment variable validation
  • Sourcemap processing

💡 Motivation and Context

Fixes https://linear.app/getsentry/issue/RN-485/command-injection-vulnerabilities-in-getsentrysentry-react-native-in-7

💚 How did you test it?

Added unit tests

📝 Checklist

  • I added tests to verify changes
  • No new PII added or SDK only sends newly added PII if sendDefaultPII is enabled
  • I updated the docs if needed.
  • I updated the wizard if needed.
  • All tests passing
  • No breaking changes

🔮 Next steps

#skip-changelog

Replaced execSync with spawnSync to eliminate shell command injection
vulnerability. Arguments are now passed as an array directly to the
binary, preventing any shell metacharacter interpretation.

Security improvements:
- No shell invocation - uses spawnSync instead of execSync
- Arguments passed as array, not string concatenation
- Eliminates need for platform-specific escaping
- Immune to command injection by design

Added comprehensive test suite with 12 tests covering:
- Basic functionality (uploads, error handling)
- Security (command injection prevention)
- Hermes support (--debug-id-reference flag)
- Environment variable validation
- Sourcemap processing

All tests pass. No behavior changes for legitimate use cases.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
@linear
Copy link

linear bot commented Feb 9, 2026

@github-actions
Copy link
Contributor

github-actions bot commented Feb 9, 2026

Semver Impact of This PR

None (no version bump detected)

📋 Changelog Preview

This is how your changes will appear in the changelog.
Entries from this PR are highlighted with a left border (blockquote style).


This PR will not appear in the changelog.


🤖 This preview updates automatically when you update the PR.

@antonis antonis added the ready-to-merge Triggers the full CI test suite label Feb 9, 2026
@github-actions
Copy link
Contributor

github-actions bot commented Feb 9, 2026

iOS (legacy) Performance metrics 🚀

  Plain With Sentry Diff
Startup time 1214.69 ms 1218.62 ms 3.94 ms
Size 3.38 MiB 4.60 MiB 1.22 MiB

Baseline results on branch: main

Startup times

Revision Plain With Sentry Diff
46da307+dirty 1217.08 ms 1224.16 ms 7.08 ms
1d62dde+dirty 1214.38 ms 1223.36 ms 8.98 ms
ebf60f9+dirty 1217.66 ms 1214.82 ms -2.84 ms
6a70a7e+dirty 1225.82 ms 1230.79 ms 4.98 ms
59f3a84+dirty 1232.56 ms 1238.12 ms 5.56 ms
86584b7+dirty 1218.82 ms 1213.38 ms -5.44 ms
4167e15+dirty 1213.39 ms 1222.50 ms 9.11 ms
a06e222+dirty 1209.75 ms 1217.82 ms 8.07 ms
7b02433+dirty 1209.39 ms 1210.90 ms 1.51 ms
f3b058c+dirty 1221.30 ms 1214.62 ms -6.68 ms

App size

Revision Plain With Sentry Diff
46da307+dirty 2.63 MiB 3.87 MiB 1.24 MiB
1d62dde+dirty 2.63 MiB 4.01 MiB 1.38 MiB
ebf60f9+dirty 3.41 MiB 4.67 MiB 1.25 MiB
6a70a7e+dirty 2.63 MiB 3.98 MiB 1.34 MiB
59f3a84+dirty 2.63 MiB 3.99 MiB 1.36 MiB
86584b7+dirty 3.44 MiB 4.59 MiB 1.15 MiB
4167e15+dirty 2.63 MiB 4.00 MiB 1.37 MiB
a06e222+dirty 3.38 MiB 4.60 MiB 1.22 MiB
7b02433+dirty 3.38 MiB 4.60 MiB 1.22 MiB
f3b058c+dirty 3.41 MiB 4.67 MiB 1.25 MiB

Previous results on branch: antonis/RN-485

Startup times

Revision Plain With Sentry Diff
49c47be+dirty 1205.90 ms 1211.51 ms 5.62 ms

App size

Revision Plain With Sentry Diff
49c47be+dirty 3.38 MiB 4.60 MiB 1.22 MiB

@github-actions
Copy link
Contributor

github-actions bot commented Feb 9, 2026

iOS (new) Performance metrics 🚀

  Plain With Sentry Diff
Startup time 1190.65 ms 1208.55 ms 17.91 ms
Size 3.38 MiB 4.60 MiB 1.22 MiB

Baseline results on branch: main

Startup times

Revision Plain With Sentry Diff
46da307+dirty 1213.45 ms 1207.96 ms -5.49 ms
1d62dde+dirty 1204.96 ms 1208.51 ms 3.55 ms
ebf60f9+dirty 1218.85 ms 1212.53 ms -6.32 ms
6a70a7e+dirty 1231.40 ms 1239.49 ms 8.09 ms
59f3a84+dirty 1205.09 ms 1213.31 ms 8.23 ms
86584b7+dirty 1199.91 ms 1210.98 ms 11.06 ms
4167e15+dirty 1228.96 ms 1242.15 ms 13.19 ms
a06e222+dirty 1216.20 ms 1222.24 ms 6.04 ms
7b02433+dirty 1202.43 ms 1210.90 ms 8.47 ms
f3b058c+dirty 1221.43 ms 1219.85 ms -1.58 ms

App size

Revision Plain With Sentry Diff
46da307+dirty 3.19 MiB 4.44 MiB 1.25 MiB
1d62dde+dirty 3.19 MiB 4.58 MiB 1.39 MiB
ebf60f9+dirty 3.41 MiB 4.67 MiB 1.25 MiB
6a70a7e+dirty 3.19 MiB 4.54 MiB 1.36 MiB
59f3a84+dirty 3.19 MiB 4.56 MiB 1.37 MiB
86584b7+dirty 3.44 MiB 4.59 MiB 1.15 MiB
4167e15+dirty 3.19 MiB 4.57 MiB 1.38 MiB
a06e222+dirty 3.38 MiB 4.60 MiB 1.22 MiB
7b02433+dirty 3.38 MiB 4.60 MiB 1.22 MiB
f3b058c+dirty 3.41 MiB 4.67 MiB 1.25 MiB

Previous results on branch: antonis/RN-485

Startup times

Revision Plain With Sentry Diff
49c47be+dirty 1197.40 ms 1203.54 ms 6.14 ms

App size

Revision Plain With Sentry Diff
49c47be+dirty 3.38 MiB 4.60 MiB 1.22 MiB

@github-actions
Copy link
Contributor

github-actions bot commented Feb 9, 2026

Android (new) Performance metrics 🚀

  Plain With Sentry Diff
Startup time 405.44 ms 464.04 ms 58.60 ms
Size 43.94 MiB 49.27 MiB 5.33 MiB

Baseline results on branch: main

Startup times

Revision Plain With Sentry Diff
7be1f99+dirty 369.02 ms 399.60 ms 30.58 ms
07808fb+dirty 392.47 ms 451.94 ms 59.47 ms
69602ce+dirty 375.37 ms 405.28 ms 29.91 ms
a02e30b+dirty 346.13 ms 381.76 ms 35.62 ms
3e0a5f9+dirty 379.92 ms 450.96 ms 71.04 ms
af9331b+dirty 374.42 ms 425.68 ms 51.26 ms
42a723e+dirty 456.38 ms 486.90 ms 30.52 ms
11ded16+dirty 309.23 ms 310.55 ms 1.33 ms
e07935d+dirty 380.10 ms 377.48 ms -2.62 ms
21c9e75+dirty 356.73 ms 381.06 ms 24.33 ms

App size

Revision Plain With Sentry Diff
7be1f99+dirty 7.15 MiB 8.42 MiB 1.27 MiB
07808fb+dirty 7.15 MiB 8.43 MiB 1.28 MiB
69602ce+dirty 7.15 MiB 8.41 MiB 1.26 MiB
a02e30b+dirty 7.15 MiB 8.42 MiB 1.27 MiB
3e0a5f9+dirty 7.15 MiB 8.42 MiB 1.27 MiB
af9331b+dirty 7.15 MiB 8.41 MiB 1.26 MiB
42a723e+dirty 43.94 MiB 49.27 MiB 5.33 MiB
11ded16+dirty 7.15 MiB 8.46 MiB 1.31 MiB
e07935d+dirty 43.94 MiB 48.82 MiB 4.88 MiB
21c9e75+dirty 7.15 MiB 8.42 MiB 1.27 MiB

Previous results on branch: antonis/RN-485

Startup times

Revision Plain With Sentry Diff
49c47be+dirty 368.16 ms 409.38 ms 41.22 ms

App size

Revision Plain With Sentry Diff
49c47be+dirty 43.94 MiB 49.27 MiB 5.33 MiB

@github-actions
Copy link
Contributor

github-actions bot commented Feb 9, 2026

Android (legacy) Performance metrics 🚀

  Plain With Sentry Diff
Startup time 420.13 ms 447.15 ms 27.02 ms
Size 43.75 MiB 48.41 MiB 4.66 MiB

Baseline results on branch: main

Startup times

Revision Plain With Sentry Diff
ec14be7+dirty 403.50 ms 411.46 ms 7.96 ms
42a723e+dirty 463.32 ms 479.53 ms 16.21 ms
170d5ea+dirty 407.92 ms 422.49 ms 14.57 ms
e07935d+dirty 448.82 ms 489.10 ms 40.29 ms
8d0a325+dirty 406.48 ms 415.02 ms 8.54 ms
90afdd3+dirty 375.94 ms 377.52 ms 1.58 ms
8db9631+dirty 442.78 ms 461.96 ms 19.18 ms
f234eb4+dirty 407.62 ms 429.64 ms 22.02 ms
7b02433+dirty 502.31 ms 556.24 ms 53.93 ms
9bf5446+dirty 442.47 ms 452.14 ms 9.67 ms

App size

Revision Plain With Sentry Diff
ec14be7+dirty 17.75 MiB 19.69 MiB 1.94 MiB
42a723e+dirty 43.75 MiB 48.41 MiB 4.66 MiB
170d5ea+dirty 17.75 MiB 19.70 MiB 1.95 MiB
e07935d+dirty 43.75 MiB 47.99 MiB 4.24 MiB
8d0a325+dirty 43.75 MiB 48.08 MiB 4.33 MiB
90afdd3+dirty 17.75 MiB 19.70 MiB 1.95 MiB
8db9631+dirty 17.75 MiB 19.70 MiB 1.96 MiB
f234eb4+dirty 17.75 MiB 19.74 MiB 1.99 MiB
7b02433+dirty 43.75 MiB 48.55 MiB 4.80 MiB
9bf5446+dirty 43.75 MiB 48.04 MiB 4.29 MiB

Previous results on branch: antonis/RN-485

Startup times

Revision Plain With Sentry Diff
49c47be+dirty 414.26 ms 466.73 ms 52.48 ms

App size

Revision Plain With Sentry Diff
49c47be+dirty 43.75 MiB 48.41 MiB 4.66 MiB

@antonis antonis marked this pull request as ready for review February 9, 2026 14:44
Copy link
Collaborator

@lucas-zimerman lucas-zimerman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@antonis antonis enabled auto-merge (squash) February 10, 2026 15:18
@antonis antonis merged commit 510b964 into main Feb 10, 2026
71 checks passed
@antonis antonis deleted the antonis/RN-485 branch February 10, 2026 15:21
try {
const stdOutBuffer = execSync('npx expo config --json');
const config = JSON.parse(stdOutBuffer.toString());
const result = spawnSync('npx', ['expo', 'config', '--json'], { encoding: 'utf8' });
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: The spawnSync('npx', ...) call will fail on Windows because npx is not a native executable and spawnSync is called without the shell: true option.
Severity: MEDIUM

Suggested Fix

For the spawnSync call involving npx, either set the shell option to true or conditionally use npx.cmd on Windows platforms to ensure the command can be resolved.

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.

Location: packages/core/scripts/expo-upload-sourcemaps.js#L19

Potential issue: On Windows, the `spawnSync` call to `npx` on line 19 will fail with an
`ENOENT` error. This occurs because `npx` is a `.cmd` script on Windows, and `spawnSync`
is called without `shell: true`, preventing it from resolving the command. This bug is
triggered when the script needs to fall back to fetching configuration via `expo config`
because environment variables like `SENTRY_ORG` or `SENTRY_PROJECT` are not set. This
will prevent Windows users from using the automatic configuration fallback feature.

Did we get this right? 👍 / 👎 to inform future reviews.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

claude-code-assisted ready-to-merge Triggers the full CI test suite

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants